//
// Created by Administrator on 2024/10/18.
//

#ifndef INFERIOR_HPP
#define INFERIOR_HPP

#include <memory>

#include "base.hpp"
#include "client.hpp"
#include "server.hpp"

namespace network {

class Inferior{
public:
    Inferior(asio::io_context &io_context, uint16_t port)
        : io_context_(io_context) {
        server_ = std::make_shared<Server>(io_context_, port,
            [this](std::shared_ptr<protocol::Container<char>> message, std::shared_ptr<Session> session) {
                this->reply(*message, *session);
            });
        client_ = std::make_shared<Client>(io_context_, JTT809LinkType::main);
    }

    bool connect(const std::string &host, const std::string &port) {
        host_ = host;
        port_ = port;
        client_->set_remote(host, port);
        try {
            client_->connect();
            return true;
        } catch (const std::exception &e) {
            logger->error(e.what());
            return false;
        }
    }

    [[nodiscard]] bool wait_for(const JTT809Bodies type = JTT809Bodies::ANY) const {
        return server_->wait_for_next(type) || client_->wait_for_next(type);
    }

    bool login(uint32_t user_id, const char password[8], uint32_t msg_gusscenter_id,
    const char down_link_ip[32], uint16_t port, const bool await = true) const {
        const std::shared_ptr<JTT809Body> bd = std::make_shared<protocol::JTT809_0x1001>(
            user_id, password,msg_gusscenter_id, down_link_ip, port);
        const auto packet = MessageFactory::packet(bd);
        deliver(packet);
        if (await) {
            return client_->wait_for_next(JTT809Bodies::UP_CONNECT_RSP);
        }
        return false;
    }

    void deliver(Packet packet) const {
        logger->debug("send a message via main link");
        client_->deliver(*packet);
    }

    void deliver(std::string &to_write) const {
        client_->deliver(to_write);
    }

    void send(Packet packet, Session &session) {
        logger->debug("send a message via subordinate link");
        session.send(packet);
    }

    void close() {
        client_->stop();
    }

private:
    void reply(const protocol::Container<char> &message, Session &session) {
        auto gateway = Gateway(message.data, message._size);
        if (const auto to_reply = gateway.route()) {
            to_reply->get_body()->link_type() == JTT809LinkType::subordinate ? send(to_reply, session) : deliver(to_reply);
        }
    }

    asio::io_context &io_context_;
    std::shared_ptr<Server> server_;
    std::shared_ptr<Client> client_;
    std::string host_ = "localhost", port_ = "12345";
    bool logged_in = false;

    Logger logger = JTT809Logger::logger("Inferior");
};

}

#endif //INFERIOR_HPP
